86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
|
|
"use server";
|
||
|
|
|
||
|
|
import { redirect } from "next/navigation";
|
||
|
|
import PocketBase from "pocketbase";
|
||
|
|
import { z } from "zod";
|
||
|
|
import { PB_URL } from "@/lib/pocketbase";
|
||
|
|
import { clearAuthCookie, setAuthCookie } from "@/lib/auth";
|
||
|
|
|
||
|
|
const loginSchema = z.object({
|
||
|
|
identity: z.string().min(1, "Username or email is required"),
|
||
|
|
password: z.string().min(1, "Password is required"),
|
||
|
|
});
|
||
|
|
|
||
|
|
export type LoginResult = { ok: true } | { ok: false; error: string };
|
||
|
|
|
||
|
|
export async function loginAction(_: unknown, formData: FormData): Promise<LoginResult> {
|
||
|
|
const parsed = loginSchema.safeParse({
|
||
|
|
identity: formData.get("identity"),
|
||
|
|
password: formData.get("password"),
|
||
|
|
});
|
||
|
|
if (!parsed.success) {
|
||
|
|
return { ok: false, error: parsed.error.issues[0]?.message ?? "Invalid input" };
|
||
|
|
}
|
||
|
|
|
||
|
|
const pb = new PocketBase(PB_URL);
|
||
|
|
try {
|
||
|
|
const auth = await pb.collection("users").authWithPassword(parsed.data.identity, parsed.data.password);
|
||
|
|
if (!auth?.token) {
|
||
|
|
return { ok: false, error: "Invalid username or password" };
|
||
|
|
}
|
||
|
|
await setAuthCookie(auth.token);
|
||
|
|
} catch (err: any) {
|
||
|
|
return { ok: false, error: "Invalid username or password" };
|
||
|
|
}
|
||
|
|
redirect("/dashboard");
|
||
|
|
}
|
||
|
|
|
||
|
|
const registerSchema = z
|
||
|
|
.object({
|
||
|
|
name: z.string().min(1, "Name is required"),
|
||
|
|
username: z.string().min(3, "Username must be at least 3 characters"),
|
||
|
|
email: z.string().email("Valid email required"),
|
||
|
|
password: z.string().min(8, "Password must be at least 8 characters"),
|
||
|
|
confirm: z.string().min(1, "Please confirm your password"),
|
||
|
|
})
|
||
|
|
.refine((d) => d.password === d.confirm, { message: "Passwords do not match", path: ["confirm"] });
|
||
|
|
|
||
|
|
export type RegisterResult = { ok: true } | { ok: false; error: string };
|
||
|
|
|
||
|
|
export async function registerAction(_: unknown, formData: FormData): Promise<RegisterResult> {
|
||
|
|
const parsed = registerSchema.safeParse({
|
||
|
|
name: formData.get("name"),
|
||
|
|
username: formData.get("username"),
|
||
|
|
email: formData.get("email"),
|
||
|
|
password: formData.get("password"),
|
||
|
|
confirm: formData.get("confirm"),
|
||
|
|
});
|
||
|
|
if (!parsed.success) {
|
||
|
|
return { ok: false, error: parsed.error.issues[0]?.message ?? "Invalid input" };
|
||
|
|
}
|
||
|
|
|
||
|
|
const pb = new PocketBase(PB_URL);
|
||
|
|
try {
|
||
|
|
await pb.collection("users").create({
|
||
|
|
email: parsed.data.email,
|
||
|
|
username: parsed.data.username,
|
||
|
|
password: parsed.data.password,
|
||
|
|
passwordConfirm: parsed.data.confirm,
|
||
|
|
name: parsed.data.name,
|
||
|
|
emailVisibility: true,
|
||
|
|
verified: true,
|
||
|
|
});
|
||
|
|
// Auto-login
|
||
|
|
const auth = await pb.collection("users").authWithPassword(parsed.data.email, parsed.data.password);
|
||
|
|
await setAuthCookie(auth.token);
|
||
|
|
} catch (err: any) {
|
||
|
|
return { ok: false, error: err?.response?.message ?? "Could not create account" };
|
||
|
|
}
|
||
|
|
redirect("/dashboard");
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function logoutAction() {
|
||
|
|
await clearAuthCookie();
|
||
|
|
redirect("/login");
|
||
|
|
}
|