diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..e4b4310
--- /dev/null
+++ b/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,5 @@
+import { handlers } from '@/auth';
+
+export const { GET, POST } = handlers;
+
+export const runtime = 'edge';
diff --git a/app/sign-in/page.tsx b/app/sign-in/page.tsx
new file mode 100644
index 0000000..b98cc25
--- /dev/null
+++ b/app/sign-in/page.tsx
@@ -0,0 +1,77 @@
+import { GithubIcon } from 'lucide-react';
+import Image from 'next/image';
+import React from 'react';
+
+import { signIn } from '@/auth';
+import { Button } from '@/components/ui/button';
+
+const SignInPage = () => {
+ return (
+
+
+
+ Welcome Back!
+
+
+ Sign in to access your personalized dashboard, manage your tasks, and
+ stay on top of your projects. Let's get started!
+
+
+
+
+
+
+ Sign in to your account
+
+
+
+
+
+ );
+};
+
+export default SignInPage;
diff --git a/auth.ts b/auth.ts
new file mode 100644
index 0000000..a54d73a
--- /dev/null
+++ b/auth.ts
@@ -0,0 +1,18 @@
+import { PrismaAdapter } from '@auth/prisma-adapter';
+import NextAuth from 'next-auth';
+import Github from 'next-auth/providers/github';
+import Google from 'next-auth/providers/google';
+
+import prisma from './prisma/client';
+
+export const { handlers, signIn, signOut, auth } = NextAuth({
+ providers: [Google, Github],
+ adapter: PrismaAdapter(prisma),
+ pages: { signIn: '/sign-in' },
+ session: { strategy: 'jwt' },
+ callbacks: {
+ authorized: async ({ auth: session }) => {
+ return !!session;
+ },
+ },
+});
diff --git a/middleware.ts b/middleware.ts
new file mode 100644
index 0000000..5966cee
--- /dev/null
+++ b/middleware.ts
@@ -0,0 +1,16 @@
+import { NextResponse } from 'next/server';
+
+import { auth } from '@/auth';
+
+export default auth((req) => {
+ if (!req.auth && !['/sign-in', '/'].includes(req.nextUrl.pathname)) {
+ const newUrl = new URL('/sign-in', req.nextUrl.origin);
+ return NextResponse.redirect(newUrl);
+ }
+
+ return NextResponse.next();
+});
+
+export const config = {
+ matcher: ['/dashboard/(.*)'],
+};
diff --git a/package.json b/package.json
index c898079..bd4ab80 100644
--- a/package.json
+++ b/package.json
@@ -15,10 +15,12 @@
"node": ">=18.18.0"
},
"dependencies": {
+ "@auth/prisma-adapter": "^2.4.2",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/utilities": "^3.2.2",
"@hookform/resolvers": "^3.9.0",
- "@prisma/client": "^5.17.0",
+ "@prisma/client": "5.18.0",
+ "@prisma/extension-accelerate": "^1.1.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",
@@ -34,6 +36,7 @@
"lucide-react": "^0.414.0",
"nanoid": "^5.0.7",
"next": "14.2.5",
+ "next-auth": "^5.0.0-beta.9",
"nextjs-toploader": "^1.6.12",
"prisma": "^5.17.0",
"react": "^18",
diff --git a/prisma/client.ts b/prisma/client.ts
index e5d7482..4bc0ef8 100644
--- a/prisma/client.ts
+++ b/prisma/client.ts
@@ -1,7 +1,8 @@
-import { PrismaClient } from "@prisma/client";
+import { PrismaClient } from '@prisma/client/edge';
+import { withAccelerate } from '@prisma/extension-accelerate';
const prismaClientSingleton = () => {
- return new PrismaClient();
+ return new PrismaClient().$extends(withAccelerate());
};
declare const globalThis: {
@@ -12,4 +13,4 @@ const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();
export default prisma;
-if (process.env.NODE_ENV !== "production") globalThis.prismaGlobal = prisma;
+if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma;
diff --git a/prisma/migrations/20240817143611_added_user_models/migration.sql b/prisma/migrations/20240817143611_added_user_models/migration.sql
new file mode 100644
index 0000000..9a11d83
--- /dev/null
+++ b/prisma/migrations/20240817143611_added_user_models/migration.sql
@@ -0,0 +1,61 @@
+-- CreateTable
+CREATE TABLE "User" (
+ "id" TEXT NOT NULL,
+ "name" TEXT,
+ "email" TEXT NOT NULL,
+ "emailVerified" TIMESTAMP(3),
+ "image" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "User_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "Account" (
+ "userId" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
+ "provider" TEXT NOT NULL,
+ "providerAccountId" TEXT NOT NULL,
+ "refresh_token" TEXT,
+ "access_token" TEXT,
+ "expires_at" INTEGER,
+ "token_type" TEXT,
+ "scope" TEXT,
+ "id_token" TEXT,
+ "session_state" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "Account_pkey" PRIMARY KEY ("provider","providerAccountId")
+);
+
+-- CreateTable
+CREATE TABLE "Session" (
+ "sessionToken" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "expires" TIMESTAMP(3) NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "VerificationToken" (
+ "identifier" TEXT NOT NULL,
+ "token" TEXT NOT NULL,
+ "expires" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "VerificationToken_pkey" PRIMARY KEY ("identifier","token")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
+
+-- AddForeignKey
+ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/prisma/migrations/20240817154924_jugar/migration.sql b/prisma/migrations/20240817154924_jugar/migration.sql
new file mode 100644
index 0000000..7212c74
--- /dev/null
+++ b/prisma/migrations/20240817154924_jugar/migration.sql
@@ -0,0 +1,13 @@
+/*
+ Warnings:
+
+ - The primary key for the `Account` table will be changed. If it partially fails, the table could be left without primary key constraint.
+ - You are about to drop the column `providerAccountId` on the `Account` table. All the data in the column will be lost.
+ - Added the required column `provider_account_id` to the `Account` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE "Account" DROP CONSTRAINT "Account_pkey",
+DROP COLUMN "providerAccountId",
+ADD COLUMN "provider_account_id" TEXT NOT NULL,
+ADD CONSTRAINT "Account_pkey" PRIMARY KEY ("provider", "provider_account_id");
diff --git a/prisma/migrations/20240817155853_revert_jugar/migration.sql b/prisma/migrations/20240817155853_revert_jugar/migration.sql
new file mode 100644
index 0000000..ab2ee66
--- /dev/null
+++ b/prisma/migrations/20240817155853_revert_jugar/migration.sql
@@ -0,0 +1,13 @@
+/*
+ Warnings:
+
+ - The primary key for the `Account` table will be changed. If it partially fails, the table could be left without primary key constraint.
+ - You are about to drop the column `provider_account_id` on the `Account` table. All the data in the column will be lost.
+ - Added the required column `providerAccountId` to the `Account` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE "Account" DROP CONSTRAINT "Account_pkey",
+DROP COLUMN "provider_account_id",
+ADD COLUMN "providerAccountId" TEXT NOT NULL,
+ADD CONSTRAINT "Account_pkey" PRIMARY KEY ("provider", "providerAccountId");
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 833e30c..531b655 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -1,5 +1,6 @@
generator client {
- provider = "prisma-client-js"
+ provider = "prisma-client-js"
+ previewFeatures = ["driverAdapters"]
}
datasource db {
@@ -48,3 +49,56 @@ enum Label {
FEATURE
DOCUMENTATION
}
+
+// users
+
+model User {
+ id String @id @default(cuid())
+ name String?
+ email String @unique
+ emailVerified DateTime?
+ image String?
+ accounts Account[]
+ sessions Session[]
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model Account {
+ userId String
+ type String
+ provider String
+ providerAccountId String
+ refresh_token String?
+ access_token String?
+ expires_at Int?
+ token_type String?
+ scope String?
+ id_token String?
+ session_state String?
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@id([provider, providerAccountId])
+}
+
+model Session {
+ sessionToken String @unique
+ userId String
+ expires DateTime
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model VerificationToken {
+ identifier String
+ token String
+ expires DateTime
+
+ @@id([identifier, token])
+}
diff --git a/public/google_icon.svg b/public/google_icon.svg
new file mode 100644
index 0000000..c0669b3
--- /dev/null
+++ b/public/google_icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/sign-in-image.svg b/public/sign-in-image.svg
new file mode 100644
index 0000000..3d15845
--- /dev/null
+++ b/public/sign-in-image.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index af76f05..39654d3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7,6 +7,26 @@
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
+"@auth/core@0.34.2":
+ version "0.34.2"
+ resolved "https://registry.yarnpkg.com/@auth/core/-/core-0.34.2.tgz#645fd1f972842ca473d110a34a5a36838209bf10"
+ integrity sha512-KywHKRgLiF3l7PLyL73fjLSIBe1YNcA6sMeew4yMP6cfCWGXZrkkXd32AjRi1hlJ9nvovUBGZHvbn+LijO6ZeQ==
+ dependencies:
+ "@panva/hkdf" "^1.1.1"
+ "@types/cookie" "0.6.0"
+ cookie "0.6.0"
+ jose "^5.1.3"
+ oauth4webapi "^2.10.4"
+ preact "10.11.3"
+ preact-render-to-string "5.2.3"
+
+"@auth/prisma-adapter@^2.4.2":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@auth/prisma-adapter/-/prisma-adapter-2.4.2.tgz#e1a30de0a3df2fbc6eda348b83b9338672a33b08"
+ integrity sha512-QQwnGYfDiyTcAxMVhTrim+lLFFA3TKq3nIrbPtGZXlkiuNQ5t0rUg//Km7Wv21pD5bxhy4aRPlfq7TdFKk3XIw==
+ dependencies:
+ "@auth/core" "0.34.2"
+
"@dnd-kit/accessibility@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz#1054e19be276b5f1154ced7947fc0cb5d99192e0"
@@ -235,6 +255,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@panva/hkdf@^1.1.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.2.1.tgz#cb0d111ef700136f4580349ff0226bf25c853f23"
+ integrity sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==
+
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
@@ -245,7 +270,7 @@
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
-"@prisma/client@^5.17.0":
+"@prisma/client@5.18.0":
version "5.18.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.18.0.tgz#526e4281a448f214c0ff81d65c39243608c98294"
integrity sha512-BWivkLh+af1kqC89zCJYkHsRcyWsM8/JHpsDMM76DjP3ZdEquJhXa4IeX+HkWPnwJ5FanxEJFZZDTWiDs/Kvyw==
@@ -270,6 +295,11 @@
"@prisma/fetch-engine" "5.18.0"
"@prisma/get-platform" "5.18.0"
+"@prisma/extension-accelerate@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@prisma/extension-accelerate/-/extension-accelerate-1.1.0.tgz#c82bb5c82185630912a5272e01f4c7b76c8a9d87"
+ integrity sha512-sESjhBZ4ywQjAVpKzsfhxyNu+9txIM5I6M1MPBaJBq/xDlqmniIAhlwIEt9KLtO80zqPxqbZYes18zrkgYqNiQ==
+
"@prisma/fetch-engine@5.18.0":
version "5.18.0"
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.18.0.tgz#5b343e2b36b27e2713901ddd032ddd6932b3d55f"
@@ -713,6 +743,11 @@
dependencies:
"@types/tern" "*"
+"@types/cookie@0.6.0":
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
+ integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
+
"@types/debug@^4.0.0":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@@ -1374,6 +1409,11 @@ confusing-browser-globals@^1.0.10:
resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81"
integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==
+cookie@0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
+ integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
+
cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -2697,6 +2737,11 @@ jiti@^1.21.0:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268"
integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
+jose@^5.1.3:
+ version "5.6.3"
+ resolved "https://registry.yarnpkg.com/jose/-/jose-5.6.3.tgz#415688bc84875461c86dfe271ea6029112a23e27"
+ integrity sha512-1Jh//hEEwMhNYPDDLwXHa2ePWgWiFNNUadVmguAAw2IJ6sj9mNxV5tGXJNqlMkJAybF6Lgw1mISDxTePP/187g==
+
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -3263,6 +3308,13 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+next-auth@^5.0.0-beta.9:
+ version "5.0.0-beta.20"
+ resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-5.0.0-beta.20.tgz#949d85fbbe3fe39b51808b8172deffc0b41e33d7"
+ integrity sha512-+48SjV9k9AtUU3JbEIa4PXNjKIewfFjVGL7Xs2RKkuQ5QqegDNIQiIG8sLk6/qo7RTScQYIGKgeQ5IuQRtrTQg==
+ dependencies:
+ "@auth/core" "0.34.2"
+
next@14.2.5:
version "14.2.5"
resolved "https://registry.yarnpkg.com/next/-/next-14.2.5.tgz#afe4022bb0b752962e2205836587a289270efbea"
@@ -3311,6 +3363,11 @@ nprogress@^0.2.0:
resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1"
integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==
+oauth4webapi@^2.10.4:
+ version "2.11.1"
+ resolved "https://registry.yarnpkg.com/oauth4webapi/-/oauth4webapi-2.11.1.tgz#8d79e6b0d54ead203094f185a11031f3f9978465"
+ integrity sha512-aNzOnL98bL6izG97zgnZs1PFEyO4WDVRhz2Pd066NPak44w5ESLRCYmJIyey8avSBPOMtBjhF3ZDDm7bIb7UOg==
+
object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -3597,6 +3654,18 @@ postcss@^8, postcss@^8.4.23, postcss@^8.4.4:
picocolors "^1.0.1"
source-map-js "^1.2.0"
+preact-render-to-string@5.2.3:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz#23d17376182af720b1060d5a4099843c7fe92fe4"
+ integrity sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==
+ dependencies:
+ pretty-format "^3.8.0"
+
+preact@10.11.3:
+ version "10.11.3"
+ resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.3.tgz#8a7e4ba19d3992c488b0785afcc0f8aa13c78d19"
+ integrity sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==
+
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -3619,6 +3688,11 @@ prettier@^3.3.3:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
+pretty-format@^3.8.0:
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385"
+ integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==
+
prisma@^5.17.0:
version "5.18.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.18.0.tgz#5ef69c802a075b7596231ea57003496873610b9e"