Implement Auth.
This commit is contained in:
parent
3c9a23481e
commit
6414307462
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 4.1 KiB |
BIN
public/images/tech_tracker_logo.png
Normal file
BIN
public/images/tech_tracker_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 386 KiB |
@ -1,19 +1,20 @@
|
||||
import "~/styles/globals.css";
|
||||
import { Inter as FontSans } from "next/font/google";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
import { type Metadata } from "next";
|
||||
export const metadata: Metadata = {
|
||||
title: "Tech Tracker",
|
||||
description: "App used by COG IT employees to update their status throughout the day.",
|
||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||
};
|
||||
|
||||
const fontSans = FontSans({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-sans",
|
||||
});
|
||||
|
||||
import { type Metadata } from "next";
|
||||
export const metadata: Metadata = {
|
||||
title: "Create T3 App",
|
||||
description: "Generated by create-t3-app",
|
||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{ children: React.ReactNode }>) {
|
||||
@ -22,10 +23,11 @@ export default function RootLayout({
|
||||
<body
|
||||
className={cn(
|
||||
"min-h-screen bg-background font-sans antialiased",
|
||||
fontSans.variable
|
||||
)}
|
||||
fontSans.variable)}
|
||||
>
|
||||
{children}
|
||||
<SessionProvider>
|
||||
{children}
|
||||
</SessionProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
@ -1,37 +1,21 @@
|
||||
import Link from "next/link";
|
||||
import { auth } from "~/auth";
|
||||
import { db } from "~/server/db";
|
||||
import No_Session from "~/components/auth/No_Session";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
|
||||
<h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]">
|
||||
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App
|
||||
</h1>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/usage/first-steps"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">First Steps →</h3>
|
||||
<div className="text-lg">
|
||||
Just the basics - Everything you need to know to set up your
|
||||
database and authentication.
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/introduction"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">Documentation →</h3>
|
||||
<div className="text-lg">
|
||||
Learn more about Create T3 App, the libraries it uses, and how to
|
||||
deploy it.
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
export default async function HomePage() {
|
||||
const user = await auth();
|
||||
const employees = await db.query.users.findMany({
|
||||
orderBy: (model, {desc}) => desc(model.id),
|
||||
});
|
||||
if (!user) {
|
||||
return (
|
||||
<No_Session />
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<main className="min-h-screen bg-gradient-to-b from-[#111111] to-[#111325] text-white">
|
||||
<h1 className="text-2xl font-semibold">Welcome!</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
10
src/components/auth/No_Session.tsx
Normal file
10
src/components/auth/No_Session.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import Sign_In from "./Sign_In";
|
||||
|
||||
export default function No_Session() {
|
||||
return (
|
||||
<div className="w-2/3 mx-auto text-center pt-10">
|
||||
<h1 className="text-2xl font-semibold">Unauthorized. Please sign in first.</h1>
|
||||
< Sign_In />
|
||||
</div>
|
||||
);
|
||||
};
|
13
src/components/auth/Sign_In.tsx
Normal file
13
src/components/auth/Sign_In.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { signIn } from "~/auth";
|
||||
|
||||
export default async function Sign_In() {
|
||||
return (
|
||||
<form className="w-full"
|
||||
action={async () => {
|
||||
"use server";
|
||||
await signIn("microsoft-entra-id");
|
||||
}}>
|
||||
<button type="submit" className="w-full">Sign In</button>
|
||||
</form>
|
||||
);
|
||||
}
|
16
src/env.js
16
src/env.js
@ -12,13 +12,13 @@ export const env = createEnv({
|
||||
.enum(["development", "test", "production"])
|
||||
.default("development"),
|
||||
API_KEY: z.string(),
|
||||
AUTH_SECRET:
|
||||
AUTH_SECRET:
|
||||
process.env.NODE_ENV === "production"
|
||||
? z.string()
|
||||
: z.string().optional(),
|
||||
AUTH_MICROSOFT_ENTRA_ID: z.string(),
|
||||
AUTH_MICROSOFT_ENTRA_SECRET: z.string(),
|
||||
AUTH_MICROSOFT_ENTRA_TENANT_ID: z.string(),
|
||||
AUTH_MICROSOFT_ENTRA_ID_ID: z.string(),
|
||||
AUTH_MICROSOFT_ENTRA_ID_SECRET: z.string(),
|
||||
AUTH_MICROSOFT_ENTRA_ID_TENANT_ID: z.string(),
|
||||
},
|
||||
|
||||
/**
|
||||
@ -38,10 +38,10 @@ export const env = createEnv({
|
||||
DATABASE_URL: process.env.DATABASE_URL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
API_KEY: process.env.API_KEY,
|
||||
AUTH_SECRET: process.env.AUTH_SECRET,
|
||||
AUTH_MICROSOFT_ENTRA_ID: process.env.AUTH_MICROSOFT_ENTRA_ID,
|
||||
AUTH_MICROSOFT_ENTRA_SECRET: process.env.AUTH_MICROSOFT_ENTRA_SECRET,
|
||||
AUTH_MICROSOFT_ENTRA_TENANT_ID: process.env.AUTH_MICROSOFT_ENTRA_TENANT_ID,
|
||||
AUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
||||
AUTH_MICROSOFT_ENTRA_ID_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_ID,
|
||||
AUTH_MICROSOFT_ENTRA_ID_SECRET: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
|
||||
AUTH_MICROSOFT_ENTRA_ID_TENANT_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
|
||||
},
|
||||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
|
||||
|
@ -1,34 +1,32 @@
|
||||
// Example model schema from the Drizzle docs
|
||||
// https://orm.drizzle.team/docs/sql-schema-declaration
|
||||
|
||||
import { sql } from "drizzle-orm";
|
||||
import {
|
||||
bigint,
|
||||
index,
|
||||
mysqlTableCreator,
|
||||
timestamp,
|
||||
varchar,
|
||||
} from "drizzle-orm/mysql-core";
|
||||
|
||||
/**
|
||||
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
|
||||
* database instance for multiple projects.
|
||||
*
|
||||
* @see https://orm.drizzle.team/docs/goodies#multi-project-schema
|
||||
*/
|
||||
export const createTable = mysqlTableCreator((name) => `tech_tracker_web_${name}`);
|
||||
export const createTable = mysqlTableCreator((name) => `${name}`);
|
||||
|
||||
export const posts = createTable(
|
||||
"post",
|
||||
export const users = createTable(
|
||||
"users",
|
||||
{
|
||||
id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
|
||||
id: bigint("id", {mode: "number"}).primaryKey().autoincrement(),
|
||||
name: varchar("name", { length: 256 }),
|
||||
createdAt: timestamp("created_at")
|
||||
status: varchar("status", { length: 256 }),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at").onUpdateNow(),
|
||||
},
|
||||
(example) => ({
|
||||
nameIndex: index("name_idx").on(example.name),
|
||||
})
|
||||
);
|
||||
|
||||
export const history = createTable(
|
||||
"history",
|
||||
{
|
||||
id: bigint("id", {mode: "number"}).primaryKey().autoincrement(),
|
||||
user_id: bigint("user_id", {mode: "number"}).references(() => users.id),
|
||||
status: varchar("status", { length: 256 }),
|
||||
updatedAt: timestamp("updated_at").notNull(),
|
||||
},
|
||||
);
|
||||
|
@ -4,6 +4,33 @@
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
@ -30,33 +57,6 @@
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
@ -66,4 +66,4 @@
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user