diff --git a/actions/auth.ts b/actions/auth.ts
new file mode 100644
index 0000000000..6523d2f8b4
--- /dev/null
+++ b/actions/auth.ts
@@ -0,0 +1,27 @@
+"use server";
+
+import { AuthError } from "next-auth";
+
+import { signIn } from "@/auth.config";
+
+// ...
+
+export async function authenticate(
+ prevState: string | undefined,
+ formData: FormData,
+) {
+ try {
+ console.log(formData);
+ await signIn("credentials", formData);
+ } catch (error) {
+ if (error instanceof AuthError) {
+ switch (error.type) {
+ case "CredentialsSignin":
+ return "Invalid credentials.";
+ default:
+ return "Something went wrong.";
+ }
+ }
+ throw error;
+ }
+}
diff --git a/actions/index.ts b/actions/index.ts
index 5532383f5f..0085735bb3 100644
--- a/actions/index.ts
+++ b/actions/index.ts
@@ -1 +1,2 @@
+export * from "./auth";
export * from "./providers";
diff --git a/app/(auth)/layout.tsx b/app/(auth)/layout.tsx
index 5ff842ef07..f1f003744e 100644
--- a/app/(auth)/layout.tsx
+++ b/app/(auth)/layout.tsx
@@ -1,6 +1,30 @@
-export const metadata = {
- title: "Next.js",
- description: "Generated by Next.js",
+import "@/styles/globals.css";
+
+import { Metadata, Viewport } from "next";
+
+import { Toaster } from "@/components/ui";
+import { fontSans } from "@/config/fonts";
+import { siteConfig } from "@/config/site";
+import { cn } from "@/lib";
+
+import { Providers } from "../providers";
+
+export const metadata: Metadata = {
+ title: {
+ default: siteConfig.name,
+ template: `%s - ${siteConfig.name}`,
+ },
+ description: siteConfig.description,
+ icons: {
+ icon: "/favicon.ico",
+ },
+};
+
+export const viewport: Viewport = {
+ themeColor: [
+ { media: "(prefers-color-scheme: light)", color: "white" },
+ { media: "(prefers-color-scheme: dark)", color: "black" },
+ ],
};
export default function RootLayout({
@@ -9,8 +33,20 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
-
{children}
+
+
+
+ {children}
+
+
+
);
}
diff --git a/app/(auth)/sign-in/page.tsx b/app/(auth)/sign-in/page.tsx
index e12af16f4c..f012c3f358 100644
--- a/app/(auth)/sign-in/page.tsx
+++ b/app/(auth)/sign-in/page.tsx
@@ -1,7 +1,9 @@
import React from "react";
+import { AuthForm } from "@/components/auth";
+
const SignIn = () => {
- return SignIn
;
+ return ;
};
export default SignIn;
diff --git a/app/(auth)/sign-up/page.tsx b/app/(auth)/sign-up/page.tsx
index b466e40354..dfe04cadeb 100644
--- a/app/(auth)/sign-up/page.tsx
+++ b/app/(auth)/sign-up/page.tsx
@@ -1,7 +1,9 @@
import React from "react";
+import { AuthForm } from "@/components/auth";
+
const SignUp = () => {
- return SignUp
;
+ return ;
};
export default SignUp;
diff --git a/auth.config.ts b/auth.config.ts
index 7baf25dd7d..58e112ef3c 100644
--- a/auth.config.ts
+++ b/auth.config.ts
@@ -1,9 +1,28 @@
-import type { NextAuthConfig } from "next-auth";
+import NextAuth, { type NextAuthConfig } from "next-auth";
+import Credentials from "next-auth/providers/credentials";
+import { z } from "zod";
export const authConfig = {
pages: {
signIn: "/sign-in",
- // signUp: "/sign-up",
+ newUser: "/sign-up",
},
- providers: [],
+ providers: [
+ Credentials({
+ async authorize(credentials) {
+ const parsedCredentials = z
+ .object({ email: z.string().email(), password: z.string().min(6) })
+ .safeParse(credentials);
+
+ if (!parsedCredentials.success) return null;
+
+ const { email, password } = parsedCredentials.data;
+ console.log("AuthConfig.ts");
+ console.log({ email, password });
+ return null;
+ },
+ }),
+ ],
} satisfies NextAuthConfig;
+
+export const { signIn, signOut, auth } = NextAuth(authConfig);
diff --git a/components/auth/AuthForm.tsx b/components/auth/AuthForm.tsx
new file mode 100644
index 0000000000..d1d7403dd1
--- /dev/null
+++ b/components/auth/AuthForm.tsx
@@ -0,0 +1,141 @@
+"use client";
+
+import { Icon } from "@iconify/react";
+import { Button, Checkbox, Divider, Input, Link } from "@nextui-org/react";
+import { useState } from "react";
+import { useFormState } from "react-dom";
+
+import { authenticate } from "@/actions";
+
+import { ProwlerExtended } from "../icons";
+import { ThemeSwitch } from "../ThemeSwitch";
+
+export const AuthForm = ({ type }: { type: string }) => {
+ const [isVisible, setIsVisible] = useState(false);
+
+ const [state, dispath] = useFormState(authenticate, undefined);
+ console.log(state);
+
+ const toggleVisibility = () => setIsVisible(!isVisible);
+
+ return (
+
+ {/* Brand Logo and ThemeSwitch */}
+
+
+ {/* Testimonial */}
+
+
+ “
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc eget
+ augue nec massa volutpat aliquet.
+ ”
+
+
+
+ {/* Login Form */}
+
+
+ {type === "sign-in" ? "Sign In" : "Sign Up"}
+
+
+ {type === "sign-in" && (
+ <>
+
+
+
+ }
+ variant="bordered"
+ >
+ Continue with Google
+
+
+ }
+ variant="bordered"
+ >
+ Continue with Github
+
+
+ >
+ )}
+ {type === "sign-in" ? (
+
+ Need to create an account?
+ Sign Up
+
+ ) : (
+
+ Already have an account?
+ Log In
+
+ )}
+
+
+ );
+};
diff --git a/components/auth/index.ts b/components/auth/index.ts
new file mode 100644
index 0000000000..1279953728
--- /dev/null
+++ b/components/auth/index.ts
@@ -0,0 +1 @@
+export * from "./AuthForm";
diff --git a/package-lock.json b/package-lock.json
index 0ce80ed402..6352893d57 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,7 +35,8 @@
"server-only": "^0.0.1",
"shadcn-ui": "^0.2.3",
"tailwind-merge": "^2.5.2",
- "tailwindcss-animate": "^1.0.7"
+ "tailwindcss-animate": "^1.0.7",
+ "zod": "^3.23.8"
},
"devDependencies": {
"@iconify/react": "^5.0.1",
diff --git a/package.json b/package.json
index 8f2d01c7c9..ab09acc019 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,8 @@
"server-only": "^0.0.1",
"shadcn-ui": "^0.2.3",
"tailwind-merge": "^2.5.2",
- "tailwindcss-animate": "^1.0.7"
+ "tailwindcss-animate": "^1.0.7",
+ "zod": "^3.23.8"
},
"devDependencies": {
"@iconify/react": "^5.0.1",