85 lines
2.1 KiB
TypeScript
85 lines
2.1 KiB
TypeScript
"use server";
|
|
|
|
import bcrypt from "bcryptjs";
|
|
|
|
import { AuthError } from "next-auth";
|
|
|
|
import { prisma } from "@/lib/db";
|
|
import { signIn, signOut } from "@/auth";
|
|
import { LoginSchema, SignupSchema } from "@/lib/validation/auth";
|
|
|
|
export type SignupState = {
|
|
error?: string;
|
|
} | undefined;
|
|
|
|
export type LoginState = {
|
|
error?: string;
|
|
} | undefined;
|
|
|
|
export async function login(
|
|
_prevState: LoginState,
|
|
formData: FormData
|
|
): Promise<LoginState> {
|
|
const parsed = LoginSchema.safeParse({
|
|
email: formData.get("email"),
|
|
password: formData.get("password"),
|
|
});
|
|
|
|
if (!parsed.success) {
|
|
return { error: parsed.error.issues[0]?.message ?? "Invalid input." };
|
|
}
|
|
|
|
try {
|
|
await signIn("credentials", {
|
|
email: parsed.data.email,
|
|
password: parsed.data.password,
|
|
redirectTo: "/",
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof AuthError) {
|
|
return { error: "Incorrect email or password." };
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function signup(
|
|
_prevState: SignupState,
|
|
formData: FormData
|
|
): Promise<SignupState> {
|
|
const parsed = SignupSchema.safeParse({
|
|
name: formData.get("name"),
|
|
email: formData.get("email"),
|
|
password: formData.get("password"),
|
|
});
|
|
|
|
if (!parsed.success) {
|
|
return { error: parsed.error.issues[0]?.message ?? "Invalid input." };
|
|
}
|
|
|
|
const { name, email, password } = parsed.data;
|
|
|
|
const existing = await prisma.user.findUnique({ where: { email } });
|
|
if (existing) {
|
|
return { error: "An account with that email already exists." };
|
|
}
|
|
|
|
const passwordHash = await bcrypt.hash(password, 12);
|
|
await prisma.user.create({ data: { name, email, passwordHash } });
|
|
|
|
try {
|
|
// Signs the user in and redirects to "/" on success. NextAuth throws a
|
|
// framework-handled redirect internally, so nothing after this runs.
|
|
await signIn("credentials", { email, password, redirectTo: "/" });
|
|
} catch (error) {
|
|
if (error instanceof AuthError) {
|
|
return { error: "Account created, but sign-in failed. Try logging in." };
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function logout() {
|
|
await signOut({ redirectTo: "/login" });
|
|
}
|