mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
chore: add AuthForm component
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./auth";
|
||||
export * from "./providers";
|
||||
|
||||
+41
-5
@@ -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 (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
<html suppressHydrationWarning lang="en">
|
||||
<head />
|
||||
<body
|
||||
suppressHydrationWarning
|
||||
className={cn(
|
||||
"min-h-screen bg-background font-sans antialiased",
|
||||
fontSans.variable,
|
||||
)}
|
||||
>
|
||||
<Providers themeProps={{ attribute: "class", defaultTheme: "dark" }}>
|
||||
{children}
|
||||
<Toaster />
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import { AuthForm } from "@/components/auth";
|
||||
|
||||
const SignIn = () => {
|
||||
return <div>SignIn</div>;
|
||||
return <AuthForm type="sign-in" />;
|
||||
};
|
||||
|
||||
export default SignIn;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import { AuthForm } from "@/components/auth";
|
||||
|
||||
const SignUp = () => {
|
||||
return <div>SignUp</div>;
|
||||
return <AuthForm type="sign-up" />;
|
||||
};
|
||||
|
||||
export default SignUp;
|
||||
|
||||
+22
-3
@@ -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);
|
||||
|
||||
@@ -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 (
|
||||
<div
|
||||
className="flex h-screen w-screen items-center justify-start overflow-hidden rounded-small bg-content1 p-2 sm:p-4 lg:p-8"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(https://nextuipro.nyc3.cdn.digitaloceanspaces.com/components-images/black-background-texture-2.jpg)",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
>
|
||||
{/* Brand Logo and ThemeSwitch */}
|
||||
<div className="absolute right-10 top-10">
|
||||
<div className="flex items-center self-center gap-4">
|
||||
<ThemeSwitch aria-label="Toggle theme" />
|
||||
<ProwlerExtended />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Testimonial */}
|
||||
<div className="absolute bottom-10 right-10 hidden md:block">
|
||||
<p className="max-w-xl text-right text-white/60">
|
||||
<span className="font-medium">“</span>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc eget
|
||||
augue nec massa volutpat aliquet.
|
||||
<span className="font-medium">”</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Login Form */}
|
||||
<div className="flex w-full max-w-sm flex-col gap-4 rounded-large bg-content1 px-8 pb-10 pt-6 shadow-small">
|
||||
<p className="pb-2 text-xl font-medium">
|
||||
{type === "sign-in" ? "Sign In" : "Sign Up"}
|
||||
</p>
|
||||
<form className="flex flex-col gap-3" action={dispath}>
|
||||
<Input
|
||||
label="Email Address"
|
||||
name="email"
|
||||
placeholder="Enter your email"
|
||||
type="email"
|
||||
variant="bordered"
|
||||
/>
|
||||
<Input
|
||||
endContent={
|
||||
<button type="button" onClick={toggleVisibility}>
|
||||
{isVisible ? (
|
||||
<Icon
|
||||
className="pointer-events-none text-2xl text-default-400"
|
||||
icon="solar:eye-closed-linear"
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
className="pointer-events-none text-2xl text-default-400"
|
||||
icon="solar:eye-bold"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
}
|
||||
label="Password"
|
||||
name="password"
|
||||
placeholder="Enter your password"
|
||||
type={isVisible ? "text" : "password"}
|
||||
variant="bordered"
|
||||
/>
|
||||
<div className="flex items-center justify-between px-1 py-2">
|
||||
<Checkbox name="remember" size="sm">
|
||||
Remember me
|
||||
</Checkbox>
|
||||
<Link className="text-default-500" href="#">
|
||||
Forgot password?
|
||||
</Link>
|
||||
</div>
|
||||
<Button color="primary" type="submit">
|
||||
{type === "sign-in" ? "Log In" : "Sign Up"}
|
||||
</Button>
|
||||
</form>
|
||||
{type === "sign-in" && (
|
||||
<>
|
||||
<div className="flex items-center gap-4 py-2">
|
||||
<Divider className="flex-1" />
|
||||
<p className="shrink-0 text-tiny text-default-500">OR</p>
|
||||
<Divider className="flex-1" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button
|
||||
startContent={
|
||||
<Icon icon="flat-color-icons:google" width={24} />
|
||||
}
|
||||
variant="bordered"
|
||||
>
|
||||
Continue with Google
|
||||
</Button>
|
||||
<Button
|
||||
startContent={
|
||||
<Icon
|
||||
className="text-default-500"
|
||||
icon="fe:github"
|
||||
width={24}
|
||||
/>
|
||||
}
|
||||
variant="bordered"
|
||||
>
|
||||
Continue with Github
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "sign-in" ? (
|
||||
<p className="text-center text-small">
|
||||
Need to create an account?
|
||||
<Link href="/sign-up">Sign Up</Link>
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-center text-small">
|
||||
Already have an account?
|
||||
<Link href="/sign-in">Log In</Link>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./AuthForm";
|
||||
Generated
+2
-1
@@ -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",
|
||||
|
||||
+2
-1
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user