setup done

This commit is contained in:
Om Lanke
2025-06-25 15:25:44 +05:30
parent ceb4b6b811
commit 2b777df5e2
55 changed files with 503 additions and 90 deletions

View File

@@ -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 (
<html lang="en" suppressHydrationWarning>
<body
className={`${fontSans.variable} ${fontMono.variable} font-sans antialiased `}
className={`${firaSans.variable} ${marcellus.variable} font-sans antialiased `}
>
<Providers>{children}</Providers>
</body>

View File

@@ -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 (
<div className="flex items-center justify-center min-h-svh">
<div className="flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl font-bold">Hello admins</h1>
<Login logIn={logIn} />
{!session?.user && <Login logIn={logIn} />}
<Studs action={getStudents} logOut={logOut} />
</div>
</div>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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).*)"],
}

19
apps/admin/next-auth.d.ts vendored Normal file
View File

@@ -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;
}
}

View File

@@ -0,0 +1,2 @@
import { handlers } from "@workspace/auth";
export const { GET, POST } = handlers;

View File

@@ -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 (
<html lang="en" suppressHydrationWarning>
<body
className={`${fontSans.variable} ${fontMono.variable} font-sans antialiased `}
className={`${firaSans.variable} ${marcellus.variable} font-sans antialiased `}
>
<Providers>{children}</Providers>
</body>

View File

@@ -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 (
<div className="flex items-center justify-center min-h-svh">
<div className="flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl font-bold">Hello students</h1>
<Button size="sm">Button</Button>
{!session?.user && <Login logIn={logIn} />}
<Studs action={getStudents} logOut={logOut} />
</div>
</div>
);

View File

@@ -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<void>}) {
return (
<form action={logIn}>
<Button
type="submit"
variant="outline"
className="w-full h-12"
>
<div className="absolute inset-0 bg-gradient-to-r from-primary/0 via-primary/10 to-primary/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700 ease-out pointer-events-none" />
<img
src="https://static.cdnlogo.com/logos/g/35/google-icon.svg"
alt="Google logo"
className="w-5 h-5 transition-transform duration-200"
/>
<span className="relative z-10 font-medium transition-colors duration-200 group-hover:text-foreground">
Sign in with Google
</span>
</Button>
</form>
);
}

View File

@@ -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 (
<div className="flex gap-2">
<Button onClick={action} variant="outline">Click me</Button>
<Button onClick={logOut}>Sign Out</Button>
</div>
);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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).*)"],
}

20
apps/student/next-auth.d.ts vendored Normal file
View File

@@ -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;
}
}